#include <stdint.h>
#include <stdio.h>
#include "string.h"
#include "md5.h"

struct KV{
    void * key;
    void * val;
};

struct KV_array{
    size_t leng;
    size_t capc;
    struct KV arr[];
};

struct KV_array *malloc_KV_array(size_t capc){
    int s=sizeof(struct KV_array)+capc*sizeof(struct KV);
    struct KV_array * ar=malloc(s);
    ar->capc=capc;
    ar->leng=0;
    return ar;
};

struct KV_array * malloc_KV_autoincr(struct KV_array * arr){
    if(arr->leng==arr->capc)   {
        arr->capc*=2;
        int s=sizeof(struct KV_array)+arr->capc*sizeof(struct KV);
        arr=realloc(arr,arr->capc);
    }
    return arr;
};

struct KV_array *arr=NULL;

insert_kv(char * k,char *v){
    size_t cur=arr->leng;
    arr->arr[cur].key=k;
    arr->arr[cur].val=v;
    arr->leng++;
}

int compar( void* a, void*b )
{
    struct KV * a1=a;
    struct KV * b1=b;
//  printf("%s comp %s\n",a1->key,b1->key);
    return strcmp(a1->key,b1->key);
}

int doin1(const char *text) {
    int state=0;   //0 start 1=>key 2=>val 3=>end
    char * ptr=text;
    char * beg=NULL;
    size_t s=strlen(text);
    char ** key=NULL;
    char ** val=NULL;

    int incr=0;
    while(ptr&&ptr!='\0'){

        if(state==0){
            if(*ptr!='{') {
                return -1;
            }
            state=1;
            ptr++;
        }
        if(state==1){
            if(*ptr!='"') {  return -2;}
            ptr++;
            beg=ptr;
            while(1){
                if(*ptr=='"')  break;
                ptr++;
            }
            if(ptr==beg)  key=strdup("");
            else          key=strndup(beg,ptr-beg);
            //printf(" key %s\n",key);
            state=2;
            ptr++;
        }
        if(state==2){
            if(*ptr!=':') {  return -3;}
            ptr++;
            if(*ptr!='"') {  return -4;}
            ptr++;
            beg=ptr;
            while(1){
                if(*ptr=='"')  break;
                ptr++;
            }

            if(ptr==beg)  val=strdup("");
            else          val=strndup(beg,ptr-beg);
            insert_kv(key,val);
            //printf(" val %s\n",val);
            ptr++;
            if(*ptr=='}') {  return 0;}   //end
            if(*ptr==','){
                state=1;
            }
            ptr++;
        }
    }
}

char * generateNormalizedString(size_t bufsize,struct KV_array * paramMap,const char *sigParamKey) {
    char *acBuf =malloc(bufsize);
    for(int i=0;i<arr->leng;i++){
            const char * key=arr->arr[i].key;
            const char * val=arr->arr[i].val;
            if(strcmp( key,sigParamKey )==0) continue;
            printf("%s=>%s\n",arr->arr[i].key,arr->arr[i].val);
        strcat(acBuf,key);
        strcat(acBuf,"=");
        strncat(acBuf,val,50);
    }
    strcat(acBuf,sigParamKey);

    return acBuf;
}

char *reverse(char *str,char *result)
{
    arr=malloc_KV_array(10);
    char *text1=str;
    doin1(text1);

    qsort(arr->arr,arr->leng,sizeof(struct KV),compar);
    for(int i=0;i<arr->leng;i++){
            printf("%s=>%s\n",arr->arr[i].key,arr->arr[i].val);
    }
    const char *ptr=generateNormalizedString(strlen(text1),arr,result);
    printf("result:%s\n",ptr);
    free(ptr);

    // char hashed1[32];
    // memset(hashed1, 0, 32);
    char *hashed1 = result;
    md5(ptr,hashed1);
    printf("result md5 re:%s\n",hashed1);
    return hashed1;
}

int main (int argc, const char * argv[]) {
    char text1[]="{\"use\":\"5\",\"mobile\":\"15199343291\",\"app_id\":\"7\"}";
    char *result = (char *)malloc((32) * sizeof(char));
    char security_key[] = "87a780";
    result = reverse(text1,security_key);
    printf("result md5s:%s\n",result);
    printf("%s\n", "test success");

    
    return 0;
}

